﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Babylon.Toolbox
{
    public class BasicEffect3Lights : ModelEffect
    {
        readonly EffectParameter worldViewProjectionParameter;
        readonly EffectParameter worldParameter;
        readonly EffectParameter booleans01Parameter;
        readonly EffectParameter diffuseColorParameter;
        readonly EffectParameter specularColorParameter;
        readonly EffectParameter specularPowerParameter;
        readonly EffectParameter shininessParameter;
        readonly EffectParameter emissiveColorParameter;
        readonly EffectParameter ambientColorParameter;
        readonly EffectParameter lightDir0Parameter;
        readonly EffectParameter lightDir1Parameter;
        readonly EffectParameter lightDir2Parameter;
        readonly EffectParameter cameraPositionParameter;

        readonly SamplerState samplerState;

        public BasicEffect3Lights(GraphicsDevice device)
            : this(device, "Babylon.Toolbox", "Effects/BasicEffect3Lights/BasicEffect3Lights")
        {
           
        }

        protected BasicEffect3Lights(GraphicsDevice device, string assemblyName, string baseName)
            : base(device, assemblyName, baseName)
        {
            worldViewProjectionParameter = GetParameter("WorldViewProjection");
            worldParameter = GetParameter("World");
            diffuseColorParameter = GetParameter("DiffuseColor");
            emissiveColorParameter = GetParameter("EmissiveColor");
            specularColorParameter = GetParameter("SpecularColor");
            specularPowerParameter = GetParameter("SpecularPower");
            shininessParameter = GetParameter("Shininess");
            ambientColorParameter = GetParameter("AmbientColor");
            booleans01Parameter = GetParameter("Booleans01");
            lightDir0Parameter = GetParameter("LightDir0");
            lightDir1Parameter = GetParameter("LightDir1");
            lightDir2Parameter = GetParameter("LightDir2");
            cameraPositionParameter = GetParameter("CameraPosition");

            samplerState = new SamplerState
            {
                AddressU = TextureAddressMode.Wrap,
                AddressV = TextureAddressMode.Wrap,
                AddressW = TextureAddressMode.Wrap,
                Filter = TextureFilter.Linear
            };

            Alpha = 1.0f;
            SpecularColor = Color.Black;
            SpecularPower = 16.0f;
            Shininess = 0.5f;
        }


        public string Name { get; set; }

        public override Matrix World { get; set; }
        public override Matrix View { get; set; }
        public override Matrix Projection { get; set; }

        public Color DiffuseColor { get; set; }
        public Texture2D DiffuseTexture { get; set; }

        public Color AmbientColor { get; set; }
        public Color SceneAmbientColor { get; set; }

        public Color EmissiveColor { get; set; }

        public Texture2D SpecularTexture { get; set; }
        public Color SpecularColor { get; set; }
        public float SpecularPower { get; set; }

        public Texture2D BumpTexture { get; set; }

        public Vector3 LightDir0 { get; set; }
        public Vector3 LightDir1 { get; set; }
        public Vector3 LightDir2 { get; set; }
        public Vector3 CameraPosition { get; set; }

        public float Shininess { get; set; }

        public float Alpha { get; set; }
        public bool InvertBinormal { get; set; }

        public override void Apply()
        {
            Vector4 booleans01 = Vector4.Zero;
            
            worldViewProjectionParameter.SetValue(World * View * Projection);
            worldParameter.SetValue(World);
            
            emissiveColorParameter.SetValue(EmissiveColor);
            specularColorParameter.SetValue(SpecularColor);
            specularPowerParameter.SetValue(new Vector4(SpecularPower,0,0,0));
            shininessParameter.SetValue(new Vector4(Shininess, 0,0,0));
            ambientColorParameter.SetValue(AmbientColor.Multiply(SceneAmbientColor));

            lightDir0Parameter.SetValue(LightDir0);
            lightDir1Parameter.SetValue(LightDir1);
            lightDir2Parameter.SetValue(LightDir2);
            cameraPositionParameter.SetValue(CameraPosition);

            if (DiffuseTexture != null)
            {
                Device.Textures[0] = DiffuseTexture;
                Device.SamplerStates[0] = samplerState;
                booleans01.X = 1.0f;
                diffuseColorParameter.SetValue(Color.White, Alpha);
            }
            else
            {
                diffuseColorParameter.SetValue(DiffuseColor, Alpha);
            }

            if (BumpTexture != null)
            {
                Device.Textures[1] = BumpTexture;
                Device.SamplerStates[1] = samplerState;
                booleans01.Y = 1.0f;
            }

            if (SpecularTexture != null)
            {
                Device.Textures[2] = SpecularTexture;
                Device.SamplerStates[2] = samplerState;
                booleans01.Z = 1.0f;
            }
            if (InvertBinormal)
                booleans01.W = 1.0f;

            booleans01Parameter.SetValue(booleans01);

            base.Apply();
        }

        public override string ToString()
        {
            return Name;
        }

        public override void Dispose()
        {
            base.Dispose();

            DiffuseTexture = null;
        }
    }
}
